//
//  ThemeManager.m
//  MultiTheme
//
//  Created by Charith Nidarsha on 6/30/14.
//  Copyright (c) 2014 Charith Nidarsha. All rights reserved.
//

#import "CNMultiThemeManager.h"

static NSString *KThemePreferenceKey        = @"cn_theme_preference_key";
static NSString *KDefaultFolderPathToThemes = @"Theme";


@interface CNMultiThemeManager() //class extension

/// holds all the color keys in the colors.plist file
@property (nonatomic, strong) NSMutableDictionary *colorKeyDictionary;

/// holds the UIColor objects for color keys.storing the keys strongly and objects weakly. as soon as UIColor deallocated its removing from this collection.
@property (nonatomic, strong) NSMapTable *currentActualColorDictionary;

/// holds all the UIImage objects for image keys. storing the keys strongly and objects weakly. as soon as UIImage deallocated its removing from this collection.
@property (nonatomic, strong) NSMapTable *currentActualImageDictionary;

/// can hold objects weakly. We dont' need to to hold the targets strongly inside this. As soon as target is dealloacated, it will be removed from here.
@property (nonatomic, strong) NSHashTable *targets;

@property (nonatomic) Theme currentTheme;
@property (nonatomic, copy) NSString *currentThemeName;
@property (nonatomic, copy) NSString *currentThemeFolderPath;
@property (nonatomic) BOOL isRetinaDisplay;

@end

@implementation CNMultiThemeManager

+ (instancetype) sharedManager
{
    static CNMultiThemeManager *manager = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        
        manager = [[self alloc] init];
    });
    return manager;
}

- (id) init
{
    if(self = [super init])
    {
        _isRetinaDisplay = ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]) && ([UIScreen mainScreen].scale == 2.0);
        _currentActualColorDictionary = [NSMapTable strongToWeakObjectsMapTable];
        _currentActualImageDictionary = [NSMapTable strongToWeakObjectsMapTable];
        _targets = [NSHashTable weakObjectsHashTable];
    }
    return self;
}

- (NSString*) folderPathToThemesFolder
{
    return KDefaultFolderPathToThemes;
}

- (void) loadTheme:(Theme)theme
{
    [self.currentActualColorDictionary  removeAllObjects];
    [self.currentActualImageDictionary removeAllObjects];
    [self.colorKeyDictionary removeAllObjects];
    
    NSString *themePath = [[self folderPathToThemesFolder] stringByAppendingPathComponent:[self nameFromTheme:theme]];
    if(themePath)
    {
        NSString *fullThemePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:themePath];
        self.colorKeyDictionary = [NSMutableDictionary dictionaryWithDictionary:[NSDictionary dictionaryWithContentsOfFile:[fullThemePath stringByAppendingPathComponent:@"Colors.plist"]]];
        
        self.currentTheme = theme;
        self.currentThemeName = [CNMultiThemeManager getThemeName:theme];
        self.currentThemeFolderPath = [fullThemePath stringByAppendingPathComponent:@"Images"];
        //[ThemeManager customizeAppearance];
    }
    
}

- (UIColor*) getColorForKey:(NSString*)strThemeKey
{
    return nil;
//    if([strThemeKey length] <=0)
//    {
//        [NSException raise:@"InvalidColorKeyException" format:@"Specified color key is not valid in getColorForKey:. Please pass a valid key"];
//    }
//    UIColor *resultColor = [self.currentActualColorDictionary objectForKey:strThemeKey];/// Load from existing one, if the color ia already loaded.
//    if(resultColor == nil)
//    {
//        NSString *strHexColor = self.colorKeyDictionary[strThemeKey];
//        if(strHexColor == nil)
//        {
//            [NSException raise:@"InvalidColorKeyException" format:@"Specified color key : %@ is not found in the colors.plist", strThemeKey];
//        }
//        UIColor *color = [CNMultiThemeManager colorWithHexString:strHexColor];
//        if(color)
//        {
//            [self.currentActualColorDictionary setObject:color forKey:strThemeKey]; // cach the color
//            return color;
//        }
//    }
//    return resultColor;
}

- (void) registerForTheme:(id<ThemeableDelegate>)delegate
{
    if(delegate)
    {
        [self.targets addObject:delegate];
        [delegate applyTheme];
//        NSLog(@"registering for theme");
    }
}

- (void) unregisterForTheme:(id<ThemeableDelegate>)delegate
{
    if(delegate)
    {
        [self.targets removeObject:delegate];
        NSLog(@"unregistering for theme");
    }
}

- (void) changeTheme:(Theme)theme
{
    [self loadTheme:theme];
    NSArray *targets = [self.targets allObjects];
    [targets enumerateObjectsUsingBlock:^(id<ThemeableDelegate> delegate, NSUInteger index, BOOL *stop){
        
        [delegate applyTheme];
    }];
}

//overiable method in subclasses
- (NSString*) nameFromTheme:(Theme)theme
{
    return [NSString stringWithFormat:@"%d",theme];
}

- (UIImage*) getImageForKey:(NSString*)strImageKey
{
//    NSFileManager *fileManager = [NSFileManager defaultManager];
//    NSString *filePathiPhone = [NSString stringWithFormat:@"%@/%@", self.currentThemeFolderPath, strImageKey];
//    UIImage *resultImage = [self.currentActualImageDictionary objectForKey:strImageKey];
//    if(resultImage == nil)
//    {
//        UIImage *image = nil;
//        if([fileManager fileExistsAtPath:filePathiPhone])
//        {
//            image = [UIImage imageWithContentsOfFile:filePathiPhone];
//        }else{
//            NSMutableString *newPath = [NSMutableString stringWithString:filePathiPhone];
//            [newPath insertString:@"@2x" atIndex:newPath.length - 4];
//            if ([fileManager fileExistsAtPath:newPath]) {
//                image = [UIImage imageWithContentsOfFile:newPath];
//            }
//        }
//        
//        if(image)
//        {
//            [self.currentActualImageDictionary setObject:image forKey:strImageKey];
//        }else{
//            image = [UIImage imageNamed:strImageKey];
//        }
//        
//        return image;
//        
//    }
    UIImage *resultImage = [UIImage imageNamed:strImageKey];
    return resultImage;
}

+ (void) customizeAppearance
{
    UIImage *navBarImage = [CNMultiThemeManager imageForKey:@"NavigationBarBg"];
    [[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsDefault];
    
    //for bar button < symbol etc
    UIColor *barButtonBackSymbolColor = [CNMultiThemeManager colorForKey:@"NAVIGATIONBAR_BAR_BACK_SYMBOL_COLOR"];
    [[UIView appearance] setTintColor:barButtonBackSymbolColor];
    
    //for bar button text colors
    UIColor *barButtonTextColor = [CNMultiThemeManager colorForKey:@"NAVIGATIONBAR_BAR_BUTTON_TEXT_COLOR"];
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : barButtonTextColor} forState:UIControlStateDisabled];
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : barButtonTextColor} forState:UIControlStateNormal];
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : barButtonTextColor} forState:UIControlStateHighlighted];
    
    //UIPopoverController customization
    UIColor *barButtonTextColorInPopOver = [CNMultiThemeManager colorForKey:@"NAVIGATIONBAR_BAR_BACK_SYMBOL_COLOR"];
    [[UIBarButtonItem appearanceWhenContainedIn:[UIPopoverController class], nil] setTitleTextAttributes:@{NSForegroundColorAttributeName : barButtonTextColorInPopOver} forState:UIControlStateNormal];
    [[UIBarButtonItem appearanceWhenContainedIn:[UIPopoverController class], nil] setTitleTextAttributes:@{NSForegroundColorAttributeName : barButtonTextColorInPopOver} forState:UIControlStateDisabled];
    [[UIBarButtonItem appearanceWhenContainedIn:[UIPopoverController class], nil] setTitleTextAttributes:@{NSForegroundColorAttributeName : barButtonTextColorInPopOver} forState:UIControlStateHighlighted];
}

+ (void) applyThemeForDefaultButton:(UIButton*)button
{
    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    UIImage *defaultImage = [CNMultiThemeManager imageForKey:@"Button"];
    defaultImage = [defaultImage resizableImageWithCapInsets:UIEdgeInsetsMake(15, 15, 15, 15)];
    [button setBackgroundImage:defaultImage forState:UIControlStateNormal];
    [button setTitleColor:[CNMultiThemeManager colorForKey:@"DEFAULT_BUTTON_TEXT_COLOR"] forState:UIControlStateNormal];
    
    UIImage *selectedImage = [CNMultiThemeManager imageForKey:@"ButtonSelected"];
    selectedImage = [selectedImage resizableImageWithCapInsets:UIEdgeInsetsMake(15, 15, 15, 15)];
    [button setBackgroundImage:selectedImage forState:UIControlStateHighlighted];
    
    UIImage *disabledImage = [CNMultiThemeManager imageForKey:@"ButtonDisabled"];
    disabledImage = [disabledImage resizableImageWithCapInsets:UIEdgeInsetsMake(15, 15, 15, 15)];
    [button setBackgroundImage:disabledImage forState:UIControlStateDisabled];
    [button setTitleColor:[CNMultiThemeManager colorForKey:@"DEFAULT_BUTTON_TEXT_DISABLED_COLOR"] forState:UIControlStateDisabled];
    
    [button.titleLabel setFont:[UIFont boldSystemFontOfSize:14]];
}

- (void) clearImageCache
{
    [self.currentActualImageDictionary removeAllObjects];
}

- (void) clearColorCache
{
    //[self.colorKeyDictionary removeAllObjects];
    [self.currentActualColorDictionary removeAllObjects];
}

#pragma mark - convenient methods to access from outside
+ (void) initilaizeWithTheme:(Theme)theme
{
    [[CNMultiThemeManager sharedManager] loadTheme:theme];
}

+ (void) registerForThemeChange:(id<ThemeableDelegate>)delegate
{
    [[CNMultiThemeManager sharedManager] registerForTheme:delegate];
}

+ (void) unregisterForThemeChange:(id<ThemeableDelegate>)delegate
{
    [[CNMultiThemeManager sharedManager] unregisterForTheme:delegate];
}

+ (UIColor*) colorForKey:(NSString*)strColorKey
{
    return [[CNMultiThemeManager sharedManager] getColorForKey:strColorKey];
}

+ (UIImage*) imageForKey:(NSString*)strImageKey
{
    return [[CNMultiThemeManager sharedManager] getImageForKey:strImageKey];
}

+ (void) changeTheme:(Theme)theme
{
    [[CNMultiThemeManager sharedManager] changeTheme:theme];
}

+ (void) saveCurrentTheme
{
    [USER_DEFAULT setObject:@([CNMultiThemeManager getCurrentTheme]) forKey:KThemePreferenceKey];
    [USER_DEFAULT synchronize];
}

+ (Theme) getSavedTheme
{
    NSNumber *numTheme = [USER_DEFAULT objectForKey:KThemePreferenceKey];
    Theme theme = [numTheme integerValue];
    return theme;
}

+ (Theme) getCurrentTheme
{
    return [[CNMultiThemeManager sharedManager] currentTheme];
}

+ (NSString*) getThemeName:(Theme)theme
{
    return [[CNMultiThemeManager sharedManager] nameFromTheme:theme];
}

+ (void) respondsToMemoryWarnings
{
    [[CNMultiThemeManager sharedManager] clearColorCache];
    [[CNMultiThemeManager sharedManager] clearImageCache];
}

#pragma mark - helper methods

+ (UIColor*) colorWithHexString:(NSString*)hexString
{
    NSString *colorString = [[hexString stringByReplacingOccurrencesOfString:@"#" withString:@""] uppercaseString];
    CGFloat alpha = 1, red = 0, blue = 0, green = 0;
    switch ([colorString length])
    {
        case 3:// #RGB
            alpha = 1.0f;
            red   = [CNMultiThemeManager colorComponentFrom:colorString start:0 length:1];
            green = [CNMultiThemeManager colorComponentFrom:colorString start:1 length:1];
            blue  = [CNMultiThemeManager colorComponentFrom:colorString start:2 length:1];
            break;
            
        case 4:// #ARGB
            alpha = [CNMultiThemeManager colorComponentFrom:colorString start:0 length:1];
            red   = [CNMultiThemeManager colorComponentFrom:colorString start:1 length:1];
            green = [CNMultiThemeManager colorComponentFrom:colorString start:2 length:1];
            blue  = [CNMultiThemeManager colorComponentFrom:colorString start:3 length:1];
            break;
            
        case 6:// #RRGGBB
            alpha = 1.0f;
            red   = [CNMultiThemeManager colorComponentFrom:colorString start:0 length:2];
            green = [CNMultiThemeManager colorComponentFrom:colorString start:2 length:2];
            blue  = [CNMultiThemeManager colorComponentFrom:colorString start:4 length:2];
            break;
            
        case 8:// #RRGGBBAA
            red   = [CNMultiThemeManager colorComponentFrom:colorString start:0 length:2];
            green = [CNMultiThemeManager colorComponentFrom:colorString start:2 length:2];
            blue  = [CNMultiThemeManager colorComponentFrom:colorString start:4 length:2];
            alpha = [CNMultiThemeManager colorComponentFrom:colorString start:6 length:2];
            break;
            
        default:
            [NSException raise:@"InvalidColorKeyException" format:@"Color code %@ is invalid. It should be a hex value of the form #RBG, #ARGB, #RRGGBB, or #RRGGBBAA", hexString];
    }
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

+ (CGFloat) colorComponentFrom:(NSString*)string start:(NSUInteger)start length:(NSUInteger)length
{
    NSString *substring = [string substringWithRange:NSMakeRange(start, length)];
    NSString *fullHex = length == 2 ? substring :[NSString stringWithFormat:@"%@%@", substring, substring];
    unsigned hexComponent;
    [[NSScanner scannerWithString:fullHex] scanHexInt:&hexComponent];
    return (hexComponent / 255.0);
}

+ (iOSDeviceFamily) getCurrentDeviceFamily
{
    UIUserInterfaceIdiom idiom = UI_USER_INTERFACE_IDIOM();
    
    switch (idiom)
    {
        case UIUserInterfaceIdiomPhone:
        {
            if ([UIScreen mainScreen].scale == 2.0f)
            {
                CGSize result = [[UIScreen mainScreen] bounds].size;
                CGFloat scale = [UIScreen mainScreen].scale;
                result = CGSizeMake(result.width * scale, result.height * scale);
                
                if(result.height == 960)
                {
                    return iPhone4Retina;
                }
                if(result.height == 1136)
                {
                    return iPhone5;
                }
            }
            else
            {
                return iPhoneStandardOld;
            }
        }
            break;
            
        case UIUserInterfaceIdiomPad:
        {
            if ([UIScreen mainScreen].scale == 2.0f)
            {
                return iPadRetina;
            }
            else
            {
                return iPadStandard;
            }
        }
            break;
            
        default:
            break;
    }
    return iPhoneStandardOld;
}

@end
